<?php

namespace App\Command;

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Doctrine\DBAL\Connection;

#[AsCommand(
    name: 'sync:table:without:prefix',
    description: 'sync tables from database without prefix, db.eq_user => App\\Entity\\User for example 最后一步生成 getter/setter 代码里实现不了，需要手动执行',
)]
class SyncTableWithoutPrefixCommand extends Command
{
    private bool $force;
    private OutputInterface $output;
    private SymfonyStyle $io;
    private string $entityDir;
    private string $repositoryDir;
    private string $entityMsgDir = "src/Entity/";

    public function __construct(
        private Connection $connection
    )
    {
        parent::__construct();
        $this->entityDir = dirname(__DIR__) . "/Entity/";
        $this->repositoryDir = dirname(__DIR__) . "/Repository/";
        if (!file_exists($this->entityDir)) {
            mkdir($this->entityDir);
        }
    }


    protected function configure(): void
    {
        $this
            ->addArgument('table', InputArgument::OPTIONAL, 'table name')
            ->addOption('force', null, InputOption::VALUE_NONE, '强制修改文件名 EqUser.php->User.php');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $this->output = $output;
        $this->force = $input->getOption('force');
        $this->io = new SymfonyStyle($input, $output);
        try {
            $table = $input->getArgument('table');
            if ($table) {
                $this->biz($table);
            } else {
                $tableList = $this->connection->fetchAllNumeric("show tables");
                foreach ($tableList as $item) {
                    $this->biz($item[0]);
                }
                $command2 = $this->getApplication()->find('make:entity-repository');
                $arguments2 = [];
                $CommandInput2 = new ArrayInput($arguments2);
                $command2->run($CommandInput2, $this->output);

                // 暂时实现不了
//                $command1 = $this->getApplication()->find('make:entity');
//                $arguments1 = [
//                    'name' => 'App\\Entity\\',
//                    '--regenerate' => true,
//                    '--overwrite' => true,
//                ];
//                $CommandInput1 = new ArrayInput($arguments1);
//                $command1->run($CommandInput1, $this->output);
            }
            $this->io->success('sync complete!');
            return Command::SUCCESS;
        } catch (\Exception $e) {
            $this->io->error($e->getMessage());
            $this->io->error($e->getTrace());
            return Command::FAILURE;
        }
    }

    private function biz($table)
    {
        list($entityName, $prefix, $entityNameWithPrefix, $tableWithoutPrefix) = $this->analysisTableName($table);
        $entityFilePath = $this->entityDir . $entityName . ".php";
        $entityWithPrefixFilePath = $this->entityDir . $entityNameWithPrefix . ".php";
        if (!file_exists($entityFilePath) && !file_exists($entityWithPrefixFilePath)) {
            $this->createEntity($table);
            $this->syncEntity($table, true);
        }else{
            $this->syncEntity($table, $this->force);
        }
        $this->io->note($this->entityMsgDir . $entityName . ".php has been complete!");
    }

    /**
     * 为表名添加前缀达到忽略表前缀的目的
     *     src/Entity/User.php
     *     @ORM\Table(name="user" => @ORM\Table(name="eq_user"
     *
     * 修改文件名去掉表前缀部分达到忽略表前缀的目的（如果Entity已经在项目中引用，请慎用。调用添加参数 --force）
     *     src/Entity/EqUser.php => src/Entity/User.php
     *     @ORM\Table(name="eq_user"
     *
     * @param string $table
     * @return void
     */
    private function syncEntity(string $table, $force)
    {
        list($entityName, $prefix, $entityNameWithPrefix, $tableWithoutPrefix) = $this->analysisTableName($table);
        if ($force) {
            $entityFilePath = $this->entityDir . $entityNameWithPrefix . ".php";
            if(file_exists($entityFilePath)){
                $string = file_get_contents($entityFilePath);
            }else{
                $entityFilePath1 = $this->entityDir . $entityName . ".php";
                $string = file_get_contents($entityFilePath1);
            }
            $string = str_replace("* {$entityNameWithPrefix}", "* {$entityName}", $string);
            $string = str_replace("class {$entityNameWithPrefix}", "class {$entityName}", $string);
            $string = str_replace("App\\Repository\\{$entityNameWithPrefix}", "App\\Repository\\{$entityName}", $string);
            $string = str_replace("repositoryClass={$entityNameWithPrefix}", "repositoryClass={$entityName}", $string);
            file_put_contents($this->entityDir . $entityName . ".php", $string);
            if(file_exists($entityFilePath)){
                unlink($entityFilePath);
            }
            $repositoryFilePath = $this->repositoryDir . $entityNameWithPrefix . "Repository.php";
            if (file_exists($this->repositoryDir) && file_exists($repositoryFilePath)) {
                $string = file_get_contents($repositoryFilePath);
                $string = str_replace("App\\Entity\\{$entityNameWithPrefix}", "App\\Entity\\{$entityName}", $string);
                $string = str_replace("class {$entityNameWithPrefix}", "class {$entityName}", $string);
                $string = str_replace("{$entityNameWithPrefix}::class","{$entityName}::class", $string);
                file_put_contents($this->repositoryDir . $entityName . "Repository.php", $string);
                unlink($repositoryFilePath);
            }
        } else {
            $entityFilePath = $this->entityDir . $entityName . ".php";
            $string = file_get_contents($entityFilePath);
            $string = str_replace("name=\"$tableWithoutPrefix\"", "name=\"$table\"", $string);
            file_put_contents($this->entityDir . $entityName . ".php", $string);
        }
    }

    private function createEntity(string $table)
    {
        list($entityName, $prefix, $entityNameWithPrefix, $tableWithoutPrefix) = $this->analysisTableName($table);
        $command = $this->getApplication()->find('doctrine:mapping:import');
        $arguments = [
            'name'    => 'App\\Entity',
            'mapping-type'    => 'annotation',
            '--path'  => 'src/Entity',
            '--filter'  => $entityNameWithPrefix,
        ];
        $CommandInput = new ArrayInput($arguments);
        $command->run($CommandInput, $this->output);
    }

    /**
     * @param string $table
     * @return array
     */
    private function analysisTableName(string $table): array
    {
        $tmp = explode('_', $table);
        $entityNameWithPrefix = ucwords($table, "_");
        $prefix = array_shift($tmp);
        $entityName = ucwords(str_replace($prefix . "_", "", $table), "_");
        $entityNameWithPrefix = str_replace("_", "", $entityNameWithPrefix);
        $entityName = str_replace("_", "", $entityName);
        $tableWithoutPrefix = implode("_", $tmp);
        return [$entityName, $prefix, $entityNameWithPrefix, $tableWithoutPrefix];
    }
}
